# Custom Right-Click Menu Cleaner
# 自定义右键菜单清理工具

# Set console encoding to UTF-8 for proper Chinese character display
# 设置控制台编码为UTF-8以正确显示中文字符
$OutputEncoding = [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::InputEncoding = [System.Text.Encoding]::UTF8

# Set PowerShell output encoding
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
$PSDefaultParameterValues['*:Encoding'] = 'utf8'

# Create HKCR drive if it doesn't exist
if (-not (Get-PSDrive -Name HKCR -ErrorAction SilentlyContinue)) {
    New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT | Out-Null
}

# Check if running as administrator
function Test-Admin {
    $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

# If not admin, restart with admin privileges
if (-not (Test-Admin)) {
    Write-Host "Requesting administrator privileges..." -ForegroundColor Yellow
    try {
        $arguments = "& '" + $myinvocation.mycommand.definition + "'"
        Start-Process powershell -Verb runAs -ArgumentList $arguments
        exit
    }
    catch {
        Write-Host "Unable to get administrator privileges, please run as administrator manually." -ForegroundColor Red
        Read-Host "Press Enter to exit"
        exit
    }
}

# Set window title
$host.ui.RawUI.WindowTitle = "Custom Right-Click Menu Cleaner"

Write-Host "========================================" -ForegroundColor Green
Write-Host "  Custom Right-Click Menu Cleaner" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""

# Function to determine menu type
function Get-ContextMenuType {
    param([string]$RegistryPath)
    
    $normalizedPath = $RegistryPath.ToLower()
    
    if ($normalizedPath -like '*hkey_classes_root\directory\background\shellex\contextmenuhandlers\*') {
        return "Directory Background Right-Click Menu (ShellEx)"
    }
    elseif ($normalizedPath -like '*hkey_classes_root\directory\background\shell\*') {
        return "Directory Background Custom Right-Click Menu (Shell)"
    }
    elseif ($normalizedPath -like '*hkey_classes_root\directory\shellex\contextmenuhandlers\*') {
        return "Folder Right-Click Menu (ShellEx)"
    }
    elseif ($normalizedPath -like '*hkey_classes_root\directory\shell\*') {
        return "Folder Custom Right-Click Menu (Shell)"
    }
    elseif ($normalizedPath -like '*hkey_classes_root\drive\shellex\contextmenuhandlers\*') {
        return "Drive Right-Click Menu (ShellEx)"
    }
    elseif ($normalizedPath -like '*hkey_classes_root\*\shellex\contextmenuhandlers\*') {
        return "File Right-Click Menu (ShellEx)"
    }
    elseif ($normalizedPath -like '*hkey_classes_root\*\shell\*') {
        return "File Custom Right-Click Menu (Shell)"
    }
    elseif ($normalizedPath -like '*hkey_classes_root\drive\shell\*') {
        return "Drive Custom Right-Click Menu (Shell)"
    }
    elseif ($normalizedPath -like '*hkey_classes_root\shell\*') {
        return "Universal Right-Click Menu (Shell)"
    }
    elseif ($normalizedPath -like '*hkey_local_machine\software\classes\*') {
        return "System-level Right-Click Menu (HKLM)"
    }
    else {
        return "Unknown Type"
    }
}

# Function to safely test registry path
function Test-RegistryPath {
    param([string]$Path)
    
    try {       
        # Use reg query command for reliable detection
        $result = cmd /c "reg query `"$Path`" 2>nul"
        return $LASTEXITCODE -eq 0
        
    }
    catch {
        return $false
    }
}

# Items to delete - you can add more here (using ordered dictionary to maintain custom order)
$itemsToDelete = [ordered]@{
    'Microsoft Defender'                      = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shellex\ContextMenuHandlers\EncryptionMenu'
    'File, Thunder Upload'                      = 'HKEY_CLASSES_ROOT\*\shell\UploadToThunderPan'
    'File, Badidu f-YunShellExt'                = 'HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\YunShellExt'
    'File, Badidu f-YunShellExtContextMenu'     = 'HKEY_CLASSES_ROOT\YunShellExt.YunShellExtContextMenu'
    'File, Badidu f-YunShellExtContextMenu.1'   = 'HKEY_CLASSES_ROOT\YunShellExt.YunShellExtContextMenu.1'
    'File, wps'                                 = 'HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\Open With kwpsshellext'
    'File, PyCharm'                             = 'HKEY_CLASSES_ROOT\*\shell\Open with PyCharm'
    'File, IDEA'                                = 'HKEY_CLASSES_ROOT\*\shell\Open with IntelliJ IDEA'
    'Folder, visual studio'                     = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\AnyCode'
    'Folder, Badidu d-YunShellExtContextMenu'   = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\YunShellExt.YunShellExtContextMenu'
    'Folder, Badidu d-YunShellExtContextMenu.1' = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\YunShellExt.YunShellExtContextMenu.1'
    'Folder, Badidu d-YunShellExt'              = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shellex\ContextMenuHandlers\YunShellExt'
    'Folder, Badidu Cloud-d'                    = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\YunShellExt.YunShellExtContextMenu'
    'Folder, Badidu Cloud-d1'                   = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\YunShellExt.YunShellExtContextMenu.1'
    'Folder, Badidu Cloud'                      = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shellex\ContextMenuHandlers\YunShellExt'
    'Folder, QQMusic Play'                      = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\QQMusic.1.Play' 
    'Folder, QQMusic Add'                       = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\QQMusic.2.Add'
    'Directory background, wps'                 = 'HKEY_CLASSES_ROOT\DesktopBackground\ShellEx\ContextMenuHandlers\kdesktopshellext'
    'Directory background, Lenovo'              = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\Lenovo'
    'Directory background, git_shell'           = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\git_shell'
    'Directory background, virsual stdio'       = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\AnyCode'
    'Directory background, IDEA'                = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\IntelliJ IDEA'
    'Directory background, PyCharm'             = 'HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\PyCharm'
}

Write-Host "Starting to clean right-click menu items..." -ForegroundColor Cyan
Write-Host ""

$notFoundList = @()
$failedList = @()
$successList = @()

$notFoundCount = 0
$failedCount = 0
$successCount = 0

# Process each item
foreach ($name in $itemsToDelete.Keys) {
    $regPath = $itemsToDelete[$name]
    
    # Remove Computer prefix if exists
    if ($regPath.StartsWith("Computer\")) {
        $regPath = $regPath.Substring(9)
    }
    
    # Get menu type
    $menuType = Get-ContextMenuType -RegistryPath $regPath
    
    # Print processing info
    Write-Host "----------------------------------------------------"
    Write-Host "Processing: $name" -ForegroundColor White
    Write-Host "  Type: $menuType" -ForegroundColor Cyan
    Write-Host "  Registry Path: $regPath" -ForegroundColor Cyan
    
    try {
        # Check if registry item exists
        if (Test-RegistryPath $regPath) {
            # Delete registry item using reg delete command with proper encoding
            try {
                # Use PowerShell's Start-Process to avoid encoding issues
                Write-Host "  PowerShell Path: $regPath" -ForegroundColor Yellow
                $processInfo = Start-Process -FilePath "reg" -ArgumentList "delete", "`"$regPath`"", "/f" -Wait -PassThru -WindowStyle Hidden
                
                if ($processInfo.ExitCode -eq 0) {
                    Write-Host "  Status: SUCCESS - Deleted" -ForegroundColor Green
                    $successCount++
                    $successList += @{Name = $name; Path = $regPath; Type = $menuType }
                }
                else {
                    Write-Host "  Status: FAILED - Delete failed" -ForegroundColor Red
                    Write-Host "  Error: Registry delete command failed (Exit code: $($processInfo.ExitCode))" -ForegroundColor Red
                    $failedCount++
                    $failedList += @{Name = $name; Path = $regPath; Type = $menuType; Error = "Registry delete command failed (Exit code: $($processInfo.ExitCode))" }
                }
            }
            catch {
                Write-Host "  Status: FAILED - Delete failed" -ForegroundColor Red
                Write-Host "  Error: $($_.Exception.Message)" -ForegroundColor Red
                $failedCount++
                $failedList += @{Name = $name; Path = $regPath; Type = $menuType; Error = $_.Exception.Message }
            }
        }
        else {
            Write-Host "  Status: NOT FOUND - No need to delete" -ForegroundColor Yellow
            $notFoundCount++
            $notFoundList += @{Name = $name; Path = $regPath; Type = $menuType }
        }
    }
    catch {
        Write-Host "  Status: FAILED - Unexpected error" -ForegroundColor Red
        Write-Host "  Error: $_" -ForegroundColor Red
        $failedCount++
        $failedList += @{Name = $name; Path = $regPath; Type = $menuType; Error = $_.Exception.Message }
    }
    
    Write-Host "----------------------------------------------------"
    Write-Host ""
}

# Display detailed not found list
# if ($notFoundList.Count -gt 0) {
#     Write-Host "Items Not Found:" -ForegroundColor Yellow
#     Write-Host "=================" -ForegroundColor Yellow
#     foreach ($item in $notFoundList) {
#         Write-Host "[NOT FOUND] $($item.Name)" -ForegroundColor Yellow
#         Write-Host "  Path: $($item.Path)" -ForegroundColor Gray
#         Write-Host "  Type: $($item.Type)" -ForegroundColor Gray
#         Write-Host ""
#     }
# }

# Display detailed failed list
if ($failedList.Count -gt 0) {
    Write-Host "Failed to Delete Items:" -ForegroundColor Red
    Write-Host "=======================" -ForegroundColor Red
    foreach ($item in $failedList) {
        Write-Host "[FAILED] $($item.Name)" -ForegroundColor Red
        Write-Host "  Path: $($item.Path)" -ForegroundColor Gray
        Write-Host "  Type: $($item.Type)" -ForegroundColor Gray
        Write-Host "  Error: $($item.Error)" -ForegroundColor Red
        Write-Host ""
    }
}

# Display detailed success list
if ($successList.Count -gt 0) {
    Write-Host "Successfully Deleted Items:" -ForegroundColor Green
    Write-Host "=============================" -ForegroundColor Green
    foreach ($item in $successList) {
        Write-Host "[SUCCESS] $($item.Name)" -ForegroundColor Green
        Write-Host "  Path: $($item.Path)" -ForegroundColor Gray
        Write-Host "  Type: $($item.Type)" -ForegroundColor Gray
        Write-Host ""
    }
}


# Display results
Write-Host "========================================" -ForegroundColor Green
Write-Host "     Execution Results" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host "$($itemsToDelete.Count) items : Total" -ForegroundColor White
Write-Host "----------------------------------------" -ForegroundColor White
Write-Host "$notFoundCount items : Not found" -ForegroundColor Yellow
Write-Host "$failedCount items : Failed to delete" -ForegroundColor Red
Write-Host "$successCount items : Successfully deleted" -ForegroundColor Green
Write-Host ""

if ($successCount -gt 0) {
    Write-Host "Note: If some menu items don't disappear immediately, restart Explorer or reboot." -ForegroundColor Yellow
    Write-Host ""
}

Write-Host "All right-click menu items have been processed." -ForegroundColor Green
Write-Host "Press any key to exit..." -ForegroundColor White

# Wait for user key press
try {
    $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
}
catch {
    Read-Host "Press Enter to exit"
} 